import java.util.Vector;
import java.lang.Math;


public class State implements Comparable<State> {

    private int[] rep;
    private int[] goal;
    private Vector<State> path;
    private int depth;
    private int searchType;
    private int nextBottom;
    //This variable is for the number of BOTTOM layers already in place (i.e. a value of 1 means that the final pancake is in place).

    public State(int[] r, int[] g, int type) {
        rep = r;
        path = new Vector<State>();
        path.add(this);
        depth = 0;
        goal=g;
        searchType = type;
        nextBottom=nextBottom();
    }

    public State(State s, int[] n) {
    //n is new or current state, s is the original state
        rep = n;
        path = new Vector<State>(s.path);
        path.add(this);
        depth = s.depth+1;
        goal=s.getGoal();
        searchType = s.getType();
        nextBottom=nextBottom();
    }

    public int nextBottom(){
        //int nextBottom=rep.length-amtComplete-1;
        int nb=rep.length-1;
        for(int i=rep.length-1; i>0; i--){ //Watch for errors if nb==-1 (when the goal is reached)
            if(rep[i]==i){
                nb--;
            }
            else{
                break;
            }
        }
        //System.out.println(toString()+"\tNB = "+nb);
        return nb;
    }
    public int printPath() {
        for (State step : path){
            //Prints the cost of each node (distance + heuristic)
            System.out.print(step.toString());
            System.out.print("\tH: "+step.admisH());
            System.out.print("\tF: "+step.getF());
            System.out.println("\tDepth: " + step.getDepth());
        }
        return 0;
    }

    public int compareTo(State other) {

        if (!(other instanceof State)) {
            System.exit(3);
            return 0;
        }

//    //These parts of the comparTo shouldn't be necessary
//    // deeper is larger: Depth first, Interative Deepening, AND IDA*
//                    else if((searchType== 2)||(searchType==3)||searchType==5){
//                return ((State)other).getDepth() -depth;
//            }
//            //deeper is smaller: Breadth First
//            else if(searchType== 1){
//                return depth - ((State)other).getDepth();
//            }

            //using H: A
        else {
            return getF()-((State)other).getF();
        }

    }

    public int admisH(){
        //We cannot use any "simple" admissible heuristic!

        //Okay, the current heuristic plan
      //ignore bottoms that are in order {...3,4,5} sort of thing
   //ignore top piece wherever it is
   //next bottom, is 1 if on top and 2 if not
   //all other out of place pieces are 1
   //this is terrible, but will work ok for a bit
        int H=nextBottom;
        
        if(rep[nextBottom]!=nextBottom && rep[0]!=nextBottom){
            H+=1;
        }
        return H;
    }

//  ***GETTERS AND SETTERS***
    public int getF(){
        return admisH() + depth;
    }
    public int getDepth() {
        return depth;
    }
    public void setDepth(int depth) {
        this.depth = depth;
    }
    public Vector<State> getPath() {
        return path;
    }
    public int[] getGoal(){
              return goal;
    }
    public String toString() {
        String str;
        if(rep.length<=20){
            str="{";
            for(int i=0; i<rep.length-1; i++){
                str+=rep[i]+",";
            }
            str+=rep[rep.length-1]+"}";
        }
        else{
            str="Next Bottom: "+nextBottom;
        }
        return str;
    }
    public int[] getRep(){
        return rep;
    }
    public void setRep(int[] rep){
        for(int i=0; i<this.rep.length; i++){
            this.rep[i]=rep[i];
        }
    }
    public int getType(){
        return searchType;
    }
    public int getNextBottom(){
        return nextBottom;
    }

}